local UnitlModule = require("Lua.UnitlModule");

--第十五节 面向对象（模拟）

UnitlModule.PrintTimer();
UnitlModule.PrintOperaName("封装");

Object = {};
Object.id = 666;
 
-- {表名}:{方法名}，会自动将调用这个函数的对象
--作为第一个参数传入该函数
function Object:new()
    --self，表示默认传入函数的第一个参数
    local obj = {};
    --__index，当找不到自己的变量时，会去找
    --元表中__index指向的内容
    self.__index = self;
    setmetatable(obj,self);
    --对象就是变量，返回一个新的变量
    --返回出去的内容，本质上就是表对象
    return obj;
end

function Object:Test()
    print(self.id);
end

--myObj 里面实际存的是表obj
local myObj = Object:new();
print(myObj);
--找不到id，所以会通过元表的__index进行索引
print(myObj.id);

--给obj这个空表进行赋值，不会影响Object这个元表
myObj.id = 777;
myObj:Test();


UnitlModule.PrintOperaName("继承");

function Object:subClass(className)
    
    _G[className] = {};
    self.__index = self;
    self.base = self; --实现base关键字 

    setmetatable(_G[className],self);
end

Object:subClass("Person");
local p = Person:new();
print("继承的id:"..p.id);
p.id = 123;
print("自己的id:"..p.id);

Object:subClass("Monster");
local m = Monster:new();
print("继承的id:"..m.id);
m.id = 654;
print("自己的id:"..m.id);

UnitlModule.PrintOperaName("多态");
--相同行为，不同表象，即为多态
--相同方法，不同逻辑，即为多态


Object:subClass("GameObject");
GameObject.posX = 0;
GameObject.posY = 0;
function GameObject:Move()
    self.posX = self.posX + 1;
    self.posY = self.posY + 1;
    print(string.format("X:%d,Y:%d",self.posX,self.posY));
end;
GameObject:subClass("Player");

function Player:Move()
    --base 指的是 GameObject类
    self.base.Move(self); --对象单独调用各自的方法
    --self.base:Move(); 对象共同调用父类的方法
end
local p_1 = Player:new();
local p_2 = Player:new();

p_1:Move();
p_2:Move();


--[[
此处天坑
    function Player:Move()
        self.base:Move(); 如果这样写，则会出现不同对象使用了相同的父类方法变量
                           相当于把基类作为第一个参数传入方法中
    end
    local p_1 = Player:new();
    local p_2 = Player:new();

    p_1:Move();
    p_2:Move(); --即这里全部调用GameObject的Move方法

--]]